16-7 过渡解析官方示例:LocalStrategy与JwtStrategy
Passport策略基础详解
LocalStrategy工作机制深度解析
1. 继承PassportStrategy实现原理
Passport.js采用策略模式设计,LocalStrategy作为具体策略实现需要:
import { Strategy as LocalStrategy } from 'passport-local';
import { PassportStrategy } from '@nestjs/passport';
export class LocalAuthStrategy extends PassportStrategy(LocalStrategy) {
constructor(private readonly authService: AuthService) {
super({
usernameField: 'email', // 可自定义字段名
passwordField: 'passcode' // 默认是username/password
});
}
}
typescript
关键点:
PassportStrategy
是NestJS的包装器- 可配置字段映射(支持JSON请求体)
- 2023年新增
passReqToCallback
选项支持访问请求对象
最佳实践:
super({
passReqToCallback: true, // 可获取完整请求对象
session: false // JWT场景禁用session
});
typescript
2. validate方法高级实现
实际项目中的validate方法需要考虑:
async validate(
request: Request, // 当passReqToCallback=true时可用
username: string,
password: string
) {
// 1. 防止时序攻击
const user = await this.authService.findUserSafe(username);
// 2. 使用bcrypt的恒定时间比较
const isValid = await compareTimingSafe(password, user?.password || '');
// 3. 记录审计日志
if (!isValid) {
await this.auditService.logFailedLogin(username, request.ip);
}
// 4. 返回标准化用户对象
return isValid ? pick(user, ['id', 'roles']) : null;
}
typescript
安全增强:
- 使用
crypto.timingSafeEqual
替代普通比较 - 返回最小化用户数据(避免密码泄漏)
3. DI容器高级用法
现代NestJS推荐使用依赖注入的最佳实践:
@Injectable()
export class LocalAuthStrategy extends PassportStrategy(Strategy) {
constructor(
@Inject(forwardRef(() => AuthService))
private authService: AuthService,
private configService: ConfigService
) {
super(configService.get('auth.local'));
}
}
@Module({
providers: [
{
provide: 'STRATEGY_OPTIONS',
useFactory: (config: ConfigService) => config.get('auth'),
inject: [ConfigService]
},
LocalAuthStrategy
]
})
typescript
架构优势:
- 支持动态配置加载
- 解决循环依赖问题
- 策略配置集中管理
策略触发流程扩展分析
完整认证流程图解
关键过程解析
- Guard触发时机:
- 在路由处理前执行
- 可组合多个Guard(用逗号分隔)
@UseGuards(LocalAuthGuard, ThrottlerGuard)
typescript - Passport中间件工作流:
- 自动序列化/反序列化
- 支持多种认证同时存在(如JWT+Session)
- 错误处理增强:
export class LocalAuthGuard extends AuthGuard('local') { handleRequest(err, user, info) { if (err || !user) { throw new UnauthorizedException('无效凭证'); } return user; } }
typescript
实战案例:多因素认证集成
结合LocalStrategy实现短信验证码登录:
async validate(username: string, password: string) {
const user = await this.validatePassword(username, password);
if (user?.enable2FA) {
const token = await this.smsService.sendVerifyCode(user.phone);
throw new ForbiddenException({
code: 'NEED_2FA',
tempToken: token
});
}
return user;
}
typescript
最新动态(2023)
- Passport v0.7+新特性:
- 支持异步策略配置
- 改进的错误处理管道
- NestJS v10优化:
- 内置策略类型检查
- 改进的DI性能
- 安全建议:
- 禁用已破解的算法(如HS256)
- 推荐使用Ed25519算法
延伸学习:
JWT认证流程深度解析
JwtStrategy解析机制进阶
令牌校验过程增强实现
- 多途径令牌提取(2023年最佳实践):
const extractors = [ ExtractJwt.fromAuthHeaderAsBearerToken(), ExtractJwt.fromUrlQueryParameter('access_token'), ExtractJwt.fromExtractors([ (req) => req.cookies?.auth_token ]) ]; super({ jwtFromRequest: ExtractJwt.fromExtractors(extractors), ignoreExpiration: false, secretOrKeyProvider: (request, rawJwt, done) => { // 动态获取密钥 const tenantId = request.headers['x-tenant-id']; this.configService.getTenantSecret(tenantId, done); } });
typescript
新特性:- 支持Header/Query/Cookie多途径获取
- 动态密钥获取(多租户系统)
- 增强签名验证:
super({ algorithms: ['ES256'], // 强制算法类型 clockTolerance: 30, // 时钟偏移容差(秒) issuer: 'myapp.com', // 签发者验证 audience: 'app.client' // 受众验证 });
typescript
安全建议:- 使用非对称加密算法(ES256/EdDSA)
- 启用完整JWT声明验证
- payload高级处理:
validate(payload: JwtPayload) { if (payload.roles.includes('banned')) { throw new ForbiddenException('账号已封禁'); } return { userId: payload.sub, meta: { lastLogin: payload.iat && new Date(payload.iat * 1000) } }; }
typescript
前端-后端交互全流程
策略协作关系增强模式
现代化登录接口实现
@Post('login')
@UseGuards(LocalAuthGuard)
@ApiOperation({ summary: '用户登录' })
async login(
@Req() req,
@Res({ passthrough: true }) res: Response
) {
const accessToken = this.jwtService.sign({
sub: req.user.userId,
roles: req.user.roles
}, {
expiresIn: '15m'
});
const refreshToken = this.jwtService.sign({
sub: req.user.userId
}, {
expiresIn: '7d'
});
// 安全设置Cookie
res.cookie('refresh_token', refreshToken, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'strict',
maxAge: 604800000
});
return { accessToken };
}
typescript
增强型受保护接口
@Get('profile')
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('user')
@ApiBearerAuth()
async getProfile(
@CurrentUser() user: JwtPayload,
@IpAddress() ip: string
) {
await this.auditService.logAccess(user.sub, ip);
return this.userService.getProfile(user.sub);
}
typescript
关键改进:
- 支持refreshToken无感刷新
- 符合OWASP安全的Cookie设置
- 自定义装饰器简化代码(@CurrentUser)
- 集成Swagger文档注解
安全增强方案
JWT最佳安全实践
// jwt.module.ts
@Module({
providers: [
{
provide: JWT_MODULE_OPTIONS,
useFactory: (config: ConfigService) => ({
publicKey: config.get('JWT_PUBLIC_KEY'),
privateKey: {
key: config.get('JWT_PRIVATE_KEY'),
passphrase: config.get('JWT_PASSPHRASE')
},
signOptions: {
algorithm: 'ES256',
issuer: 'myapp.com',
expiresIn: '15m'
},
verifyOptions: {
algorithms: ['ES256'],
clockTolerance: 30
}
}),
inject: [ConfigService]
}
]
})
typescript
防御措施清单
- 使用非对称加密算法
- 设置合理的过期时间(accessToken: 15-30分钟)
- 实现token自动刷新机制
- 记录JWT使用日志
- 提供令牌吊销接口
性能优化技巧
- 缓存公钥:
const publicKey = await this.cacheManager.wrap( 'jwt_public_key', () => this.keyService.fetchPublicKey(), { ttl: 3600 } );
typescript - 并行验证:
Promise.all([ this.jwtService.verifyAsync(token), this.checkTokenRevocation(token) ])
typescript - 精简payload:
sign(payload: UserToken) { return { sub: payload.id, roles: payload.roles, v: 2 // 版本控制 }; }
typescript
扩展阅读:
核心实现原理深度解析
DI容器高级管理机制
1. 策略注册进阶模式
多环境配置注册:
@Module({
providers: [
{
provide: 'AUTH_STRATEGIES',
useFactory: (config: ConfigService) => {
const strategies = [];
if (config.get('AUTH_LOCAL_ENABLED')) {
strategies.push(LocalStrategy);
}
if (config.get('AUTH_JWT_ENABLED')) {
strategies.push(JwtStrategy);
}
return strategies;
},
inject: [ConfigService]
}
]
})
export class AuthModule {}
typescript
动态策略加载:
constructor(
@Inject('STRATEGY_FACTORY')
private strategyFactory: StrategyFactory
) {
const strategy = strategyFactory.create('oidc');
super(strategy);
}
typescript
2. 作用域隔离增强方案
请求上下文感知:
@Injectable({ scope: Scope.REQUEST })
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(
private request: Request,
@InjectRepository(User)
private usersRepository: Repository<User>
) {
super({
jwtFromRequest: fromAuthHeaderAsBearerToken(),
secretOrKey: process.env.JWT_SECRET
});
}
}
typescript
策略路由映射表:
const strategyRouteMap = new Map([
['/auth/login', 'local'],
['/api/*', 'jwt'],
['/admin/*', 'jwt-admin']
]);
app.useGlobalGuards(new DynamicStrategyGuard(strategyRouteMap));
typescript
请求对象处理高级模式
1. 自动赋值机制扩展
多级用户对象转换:
validate(payload) {
return {
...payload,
meta: {
loginDevice: this.request.headers['user-agent'],
permissions: this.getPermissions(payload.sub)
}
};
}
typescript
类型安全的请求扩展:
declare module 'express' {
interface Request {
user: {
id: string;
roles: string[];
sessionId?: string;
};
}
}
typescript
2. 控制器访问优化方案
自定义参数装饰器:
export const CurrentUser = createParamDecorator(
(data: keyof JwtPayload | undefined, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
return data ? request.user[data] : request.user;
}
);
@Get('profile')
profile(@CurrentUser('id') userId: string) {
return this.service.getProfile(userId);
}
typescript
响应标准化处理:
@UseInterceptors(TransformInterceptor)
@Get('me')
async getMe(@CurrentUser() user) {
return {
data: await this.userService.findById(user.id),
meta: {
requestId: this.request.id
}
};
}
typescript
安全校验原理增强
1. 签名验证最佳实践
密钥轮换方案:
super({
secretOrKeyProvider: (req, token, done) => {
const keyVersion = decode(token).header.kid;
this.keyService.getKey(keyVersion, done);
}
});
typescript
算法迁移路径:
const algorithms = ['ES256', 'RS256', 'HS256']; // 优先级递减
const verifyOptions = { algorithms };
jwt.verify(token, getKey, verifyOptions);
typescript
2. 声明校验扩展实现
自定义声明验证器:
validate(payload) {
new JwtClaimsValidator()
.requireIssuer('myapp.com')
.requireAudience(['web', 'mobile'])
.checkNotBefore()
.validate(payload);
return payload;
}
typescript
JWT头验证增强:
const header = decode(token, { complete: true }).header;
assert(header.typ === 'JWT');
assert(header.alg === 'ES256');
assert(header.kid);
typescript
架构设计模式
策略生命周期管理
安全验证流程
性能优化方案
- 策略缓存机制:
const strategy = await this.cacheManager.wrap( `strategy:${strategyName}`, () => this.strategyFactory.create(strategyName), { ttl: 3600 } );
typescript - 并行验证流程:
const [signatureValid, claimsValid] = await Promise.all([ this.verifySignature(token), this.validateClaims(payload) ]);
typescript - JWT预处理中间件:
app.use((req, res, next) => { if (req.headers.authorization) { req.jwt = decode(req.headers.authorization.split(' ')[1]); } next(); });
typescript
扩展阅读:
↑